/**
 * Copyright(c) 2010 Ceno Techonologies Co., Ltd.
 *
 * History:
 *   15-6-18 下午4:11 Created by lyyang
 */
package com.jade.bss.business.bonus.impl;

import java.util.Date;
import java.util.List;
import javax.ejb.TransactionAttribute;
import javax.inject.Inject;
import javax.inject.Named;

import com.jade.bss.base.BssConstants;
import com.jade.bss.base.BssException;
import com.jade.bss.base.account.Account;
import com.jade.bss.base.account.AccountDao;
import com.jade.bss.base.account.AccountRecord;
import com.jade.bss.business.bonus.Bonus;
import com.jade.bss.business.bonus.BonusDao;
import com.jade.bss.business.bonus.BonusManager;
import com.jade.bss.business.bonus.BonusRecord;
import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.util.PagingList;
import org.springframework.transaction.annotation.Transactional;

/**
 * 红包管理实现
 *
 * @author <a href="mailto:lyyang@ceno.cn">lyyang</a>
 * @version 1.0 15-6-18 下午4:11
 */
@Named ("bss_bonusManager")
public class BonusManagerImpl
        extends BonusManager
{
    private BonusDao bonusDao;
    private AccountDao accountDao;

    @Inject
    public void setAccountDao(@Named ("bss_accountDao") AccountDao accountDao)
    {
        this.accountDao = accountDao;
    }

    @Inject
    public void setBonusDao(@Named ("bss_bonusDao") BonusDao bonusDao)
    {
        this.bonusDao = bonusDao;
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public Bonus add(Bonus bonus)
            throws BssException
    {
        Account account = accountDao.getAccount(BssConstants.OWNER_TYPE_USER, bonus.getOwnerId(),
                Account.DEFAULT_ACCOUNT_TYPE);
        if (account.getRemnant() < bonus.getTotalAmount()) {
            throw new BssException("err.bss.account.not_enough", "the account is not enough for bonus");
        }
        AccountRecord accountRecord = new AccountRecord();
        accountRecord.setOwnerId(bonus.getOwnerId());
        accountRecord.setOwnerType(BssConstants.OWNER_TYPE_USER);
        accountRecord.setType(BssConstants.OWNER_TYPE_USER);
        accountRecord.setAccountId(account.getId());
        accountRecord.setAmount(bonus.getTotalAmount());
        accountRecord.setFee(bonus.getTotalAmount());
        accountRecord.setOp(AccountRecord.ACCOUNT_BONUS);
        accountRecord.setOpDate(new Date());
        accountRecord.setParent(account.getId());
        accountRecord.setStatus(AccountRecord.RECORD_PAID);
        accountDao.addAccountRecord(accountRecord);
        accountDao.updateAccount(account, -bonus.getTotalAmount(), 0, 0);
        return bonusDao.add(bonus);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public synchronized void remove(Bonus bonus)
            throws BssException
    {
        Account account = accountDao.getAccount(BssConstants.OWNER_TYPE_USER, bonus.getOwnerId(),
                Account.DEFAULT_ACCOUNT_TYPE);
        long last = bonus.getTotalAmount() - bonus.getTotalCost();
        if (last > 0) {
            AccountRecord accountRecord = new AccountRecord();
            accountRecord.setOwnerId(bonus.getOwnerId());
            accountRecord.setOwnerType(BssConstants.OWNER_TYPE_USER);
            accountRecord.setType(BssConstants.OWNER_TYPE_USER);
            accountRecord.setAccountId(account.getId());
            accountRecord.setAmount(bonus.getTotalAmount());
            accountRecord.setFee(bonus.getTotalAmount());
            accountRecord.setOp(AccountRecord.ACCOUNT_BONUS_DELETE);
            accountRecord.setOpDate(new Date());
            accountRecord.setParent(account.getId());
            accountRecord.setStatus(AccountRecord.RECORD_PAID);
            accountDao.addAccountRecord(accountRecord);
            accountDao.updateAccount(account, last, 0, 0);
        }
        bonusDao.remove(bonus);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateRecordStatus(long id, int status)
    {
        bonusDao.updateRecordStatus(id, status);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void remove(long[] ids)
            throws BssException
    {
        for (long id : ids) {
            Bonus bonus = bonusDao.get(id);
            if (bonus != null) {
                Account account = accountDao.getAccount(BssConstants.OWNER_TYPE_USER, bonus.getOwnerId(),
                        Account.DEFAULT_ACCOUNT_TYPE);
                long last = bonus.getTotalAmount() - bonus.getTotalCost();
                if (last > 0) {
                    AccountRecord accountRecord = new AccountRecord();
                    accountRecord.setOwnerId(bonus.getOwnerId());
                    accountRecord.setOwnerType(BssConstants.OWNER_TYPE_USER);
                    accountRecord.setType(BssConstants.OWNER_TYPE_USER);
                    accountRecord.setAccountId(account.getId());
                    accountRecord.setAmount(bonus.getTotalAmount());
                    accountRecord.setFee(bonus.getTotalAmount());
                    accountRecord.setOp(AccountRecord.ACCOUNT_BONUS_DELETE);
                    accountRecord.setOpDate(new Date());
                    accountRecord.setParent(account.getId());
                    accountRecord.setStatus(AccountRecord.RECORD_PAID);
                    accountDao.addAccountRecord(accountRecord);
                    accountDao.updateAccount(account, last, 0, 0);
                }
                bonusDao.remove(bonus);
            }
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public synchronized void update(Bonus bonus)
            throws BssException
    {
        Bonus oldBonus = bonusDao.get(bonus.getId());
        if (oldBonus.getStatus() == Bonus.STATUS_PUBLISH) {
            throw new BssException("err.bss.bonus.already_publish", "the bonus is already published");
        }
        Account account = accountDao.getAccount(BssConstants.OWNER_TYPE_USER, bonus.getOwnerId(),
                Account.DEFAULT_ACCOUNT_TYPE);
        long change = bonus.getTotalAmount() - oldBonus.getTotalAmount();
        if (change > 0) {
            if (account.getRemnant() < change) {
                throw new BssException("err.bss.account.not_enough", "the account is not enough for bonus");
            }
        }
        AccountRecord accountRecord = new AccountRecord();
        accountRecord.setOwnerId(bonus.getOwnerId());
        accountRecord.setOwnerType(BssConstants.OWNER_TYPE_USER);
        accountRecord.setType(BssConstants.OWNER_TYPE_USER);
        accountRecord.setAccountId(account.getId());
        accountRecord.setAmount(-change);
        accountRecord.setFee(-change);
        accountRecord.setOp(AccountRecord.ACCOUNT_BONUS_CHANGE);
        accountRecord.setOpDate(new Date());
        accountRecord.setParent(account.getId());
        accountRecord.setStatus(AccountRecord.RECORD_PAID);
        accountDao.addAccountRecord(accountRecord);
        accountDao.updateAccount(account, -change, 0, 0);
        bonusDao.update(bonus);
    }

    public Bonus get(long id)
    {
        return bonusDao.get(id);
    }

    public PagingList<Bonus> query(Criteria criteria)
    {
        return bonusDao.query(criteria);
    }

    public List<Bonus> list(Criteria criteria)
    {
        return bonusDao.list(criteria);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void addRecord(BonusRecord record)
    {
        bonusDao.addRecord(record);
    }

    public BonusRecord getRecord(long id)
    {
        return bonusDao.getRecord(id);
    }

    public BonusRecord getRecord(String receivedType, String receivedId, String orderNo)
    {
        return bonusDao.getRecord(receivedType, receivedId, orderNo);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateRecord(BonusRecord record)
    {
        bonusDao.updateRecord(record);
    }

    public PagingList<BonusRecord> queryRecord(Criteria criteria)
    {
        return bonusDao.queryRecord(criteria);
    }

    public List<BonusRecord> listRecord(Criteria criteria)
    {
        return bonusDao.listRecord(criteria);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void draw(long id, long amount)
    {
        bonusDao.consume(id, amount);
    }

    public BonusRecord getRecord(long bonusId, String ownerType, String ownerId)
    {
        return bonusDao.getRecord(bonusId, ownerType, ownerId);
    }

    @Override
    public long statBonusRecordCount(long id, int status, Date beginDate, Date endDate)
    {
        return bonusDao.statBonusRecordCount(id, status, beginDate, endDate);
    }
}
